package com.csproj.siiat.base.common.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.csproj.basic.domain.ElectronicLockMessage;
import com.csproj.basic.domain.Path;
import com.csproj.basic.repository.ElectronicLockMessageRepository;
import com.csproj.basic.service.PathService;
import com.csproj.basic.service.mapper.ElectronicLockMessageMapper;
import com.csproj.dispatch.domain.Dispatch;
import com.csproj.dispatch.domain.WarnInfo;
import com.csproj.dispatch.repository.DispatchRepository;
import com.csproj.dispatch.service.WarnInfoService;
import com.csproj.dispatch.service.dto.WarnInfoDTO;
import com.csproj.dispatch.util.PointSurface;
import com.csproj.siiat.base.common.util.TLMessage.TLMessage;

import com.csproj.siiat.config.Languagesproperties;
import com.csproj.system.domain.Dictionary;
import com.csproj.system.domain.Language;
import com.csproj.system.repository.LanguageRepository;
import com.csproj.system.service.UserInfoService;
import com.csproj.system.service.dto.UserInfoDTO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import com.csproj.system.service.DictionaryService;

import static com.csproj.siiat.base.common.service.TCPReceiverService.MQ;

/**
 * Created by tyshi on 2018/9/26.
 * <p>
 * this will be main thread to receiving TCP heartbeat from remote
 * then validate and parse the received digits into queque
 */

@Service
public class TLMessageConsumerService {

    // please keep this TCPServer class logger here, it is not mistake but on purpose
    private final Logger logger = LoggerFactory.getLogger(TLMessageConsumerService.class);

    private final ElectronicLockMessageMapper electronicLockMessageMapper;

    private final DispatchRepository dispatchRepository;

    private final WarnInfoService warnInfoService;

    private final DictionaryService dictionaryService;

    private final PathService pathService;
    private final WebsocketUDP websocketUDP;
    private final UserInfoService userInfoService;
    private final Languagesproperties languagesproperties;
    private final LanguageRepository languageRepository;

    @Autowired
    private ElectronicLockMessageRepository electronicLockMessageRepository;

    public TLMessageConsumerService(ElectronicLockMessageMapper electronicLockMessageMapper,
                                    DispatchRepository dispatchRepository, WarnInfoService warnInfoService, DictionaryService dictionaryService, PathService pathService, WebsocketUDP websocketUDP, UserInfoService userInfoService, Languagesproperties languagesproperties, LanguageRepository languageRepository) {
        this.electronicLockMessageMapper = electronicLockMessageMapper;
        this.dispatchRepository = dispatchRepository;
        this.warnInfoService = warnInfoService;
        this.dictionaryService = dictionaryService;
        this.pathService = pathService;
        this.websocketUDP = websocketUDP;
        this.userInfoService = userInfoService;
        this.languagesproperties = languagesproperties;
        this.languageRepository = languageRepository;
    }

    // execute every 3 seconds
    @Scheduled(fixedRate = 5 * 1000)
    synchronized public void consume() {

        Map<String, Object> currentMp = new HashMap<String, Object>() {
        };
        List<Language> l = languageRepository.findByDefault();
        Language first = null;
        if (l.size() > 0) {
            first = l.get(0);
        }

        if (first != null) {
            if (first.getName().equals("zh")) {
                currentMp = languagesproperties.getZh();
            } else if (first.getName().equals("en")) {
                currentMp = languagesproperties.getEn();

            } else if (first.getName().equals("pu")) {
                currentMp = languagesproperties.getPu();
            }
        }

        List<ElectronicLockMessage> elml = new ArrayList<ElectronicLockMessage>();

        //need to test on how long the queque could be processed one time.
        logger.info("start processing queque--------------------");

        int count = 0;
        while (true) {
            TLMessage m = (TLMessage) MQ.poll();
            if (m == null) {
                logger.info(count + " messages processed in this loop");
                break;
            }
            try {
                ElectronicLockMessage electronicLockMessage = m.toDomain();
                Dispatch dispatch = dispatchRepository.findFirstByLockCodeAndDeletionTimeIsNullAndArriveTimeIsNullOrderByCreationTimeDesc(electronicLockMessage.getElNumber());
                String warnType = "0";
                if (dispatch != null) {
                    electronicLockMessage.setDispatchId(dispatch.getId());
                }

                String msg = "";
                String message = "";
                if (currentMp != null) {
                    msg += currentMp.get("lockset_no") + ":" + electronicLockMessage.getElNumber();
                    msg += "/" + currentMp.get("lockset") + currentMp.get("state") + ":";
                }


                if (electronicLockMessage.getLockStickStatus()) {
                    if (currentMp != null) {
                        msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_lever_shearing");
                        message += currentMp.get("warn_lever_shearing") + "-";
                    }
                    warnType = "2";
                }

                if (electronicLockMessage.getVolt() <= 3450) {
                    if (currentMp != null) {
                        msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_lvd").toString();
                        message += currentMp.get("warn_lvd").toString() + "-";
                    }
                    warnType = "3";
                }

                if (electronicLockMessage.getOuterStatus()) {
                    if (currentMp != null) {
                        msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_disassemble_bonnet");
                        message += currentMp.get("warn_disassemble_bonnet") + "-";
                    }
                    warnType = "1";
                }
                if (electronicLockMessage.getGpsStatus()) {
                    if (currentMp != null) {
                        msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_gps_lost");
                        message += currentMp.get("warn_gps_lost") + "-";
                    }
                    warnType = "5";
                }
                if (dispatch != null && dispatch.getExpectedarriveTime() != null) {
                    if (electronicLockMessage.getTime().isAfter(dispatch.getExpectedarriveTime())) {
                        if (currentMp != null) {
                            msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_long_time");
                            message += currentMp.get("warn_long_time") + "-";
                        }
                        warnType = "6";
                    }

                }


                Dictionary dicForPark = dictionaryService.findFirstByDictionaryName("park_time");
                Integer val = 0;
                if (dicForPark != null && electronicLockMessage.getIsMoving() == 0) {
                    String settingValue = dicForPark.getItemValue();
                    if (Integer.valueOf(settingValue) > 3) {
                        val = Integer.valueOf(settingValue) - 3;
                    } else {
                        val = 1;
                    }

                    ElectronicLockMessage ele = electronicLockMessageRepository.findFirstByDispatchIdAndElNumberAndIsMovingOrderByTimeDesc
                            (electronicLockMessage.getDispatchId(), electronicLockMessage.getElNumber(), 1);
                    if (ele != null) {
                        if (ele.getTime().plusMinutes(val).isBefore(electronicLockMessage.getTime())) {
                            if (currentMp != null) {
                                msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_park_long_time");
                                message += currentMp.get("warn_park_long_time") + "-";
                            }
                            warnType = "8";
                        }
                    }
                }

                Dictionary dicForlocation = dictionaryService.findFirstByDictionaryName("route_deviation");

                if (dispatch != null && dicForlocation != null) {
                    Path path = pathService.findOne(dispatch.getRouteId());

//                    System.out.println(path);
//                    System.out.println(dispatch);
//                    System.out.println(electronicLockMessage);

                    if (path != null) {
                        String deviation = dicForlocation.getItemValue();
                        boolean warn = true;

                        double M_PI = Math.PI;
                        if (StringUtils.isNotBlank(path.getGeoJson())) {
                            Map<String, Object> mp = (Map<String, Object>) JSONObject.parse(path.getGeoJson());
                            if (mp != null) {
                                Map<String, Object> geometry = (Map<String, Object>) mp.get("geometry");
                                if (geometry != null) {
                                    Map<String, Integer> spatialReference = (Map<String, Integer>) geometry.get("spatialReference");

                                    List<List> paths = (List<List>) geometry.get("paths");
                                    if (paths != null && paths.size() > 0) {
                                        List<List> pos = paths.get(0);
                                        if (pos != null && pos.size() > 0) {
                                            for (List sc : pos) {
                                                if (sc.size() == 2) {
                                                    if (spatialReference != null) {
                                                        if (spatialReference.get("wkid")==4326) {
                                                            Double lng = ((BigDecimal) sc.get(0)).doubleValue();
                                                            Double lat = ((BigDecimal) sc.get(1)).doubleValue();
                                                            boolean result = PointSurface.isInCircle(electronicLockMessage.getLongitude(), electronicLockMessage.getLatitude(), lng, lat, deviation);
                                                            if (result) {
                                                                warn = false;
                                                                break;
                                                            }

                                                        } else if (spatialReference.get("wkid")==102100) {
                                                            Double mklng = ((BigDecimal) sc.get(0)).doubleValue();
                                                            Double mklat = ((BigDecimal) sc.get(1)).doubleValue();


                                                            double x = mklng / 20037508.34 * 180;
                                                            double y = mklat / 20037508.34 * 180;
                                                            y = 180 / M_PI * (2 * Math.atan(Math.exp(y * M_PI / 180)) - M_PI / 2);
                                                            Double lng = x;
                                                            Double lat = y;

                                                            boolean result = PointSurface.isInCircle(electronicLockMessage.getLongitude(), electronicLockMessage.getLatitude(), lng, lat, deviation);
                                                            if (result) {
                                                                warn = false;
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            if (warn && currentMp != null) {
                                                msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_route_deviation");
                                                message += currentMp.get("warn_route_deviation") + "-";
                                                warnType = "7";
                                            }
                                        }


                                    }

                                }

                            }

                        } else {

                            if (path.getType().equals("1")) {

                            } else if (path.getType().equals("2")) {
                                List<ElectronicLockMessage> eleList = electronicLockMessageRepository.findAllByDispatchIdOrderByTimeAsc(dispatch.getId());
//                               System.out.println("调度ID：" + dispatch.getId() + "调度锁号:" + dispatch.getLockCode() + "集装箱号:" + dispatch.getContainerCode() + "偏移设置:" + deviation);
                                if (!eleList.isEmpty()) {
                                    for (ElectronicLockMessage lockMessage : eleList) {
                                        boolean result = PointSurface.isInCircle(electronicLockMessage.getLongitude(), electronicLockMessage.getLatitude(), lockMessage.getLongitude(), lockMessage.getLatitude(), deviation);
                                        if (result) {
                                            warn = false;
                                            break;
                                        }
                                    }
                                    if (warn && currentMp != null) {
                                        msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_route_deviation");
                                        message += currentMp.get("warn_route_deviation") + "-";
                                        warnType = "7";
                                    }
                                }
                            }
                        }

                    }

                    Dictionary dic = dictionaryService.findFirstByDictionaryName("over_speed");
                    if (dic != null) {
                        if (StringUtils.isNotBlank(dic.getItemValue())) {
                            try {
                                Float speed = Float.valueOf(dic.getItemValue());
                                if (electronicLockMessage.getSpeed() > speed) {

                                    if (currentMp != null) {
                                        msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("warn_overspeed");
                                        message += currentMp.get("warn_overspeed") + "-";
                                    }
                                    warnType = "4";
                                }
                            } catch (Exception e) {

                            }
                        }
                    }

                    if (currentMp != null) {
                        if (electronicLockMessage.getIsLocked()) {
                            msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("lockset_lock_success");
                            message += (msg.endsWith(":") ? "" : "-") + currentMp.get("lockset_lock_success");
                        } else {
                            msg += (msg.endsWith(":") ? "" : "-") + currentMp.get("lockset_unlock_success");
                            message += (msg.endsWith(":") ? "" : "-") + currentMp.get("lockset_lock_success");
                        }

                        msg += "-" + currentMp.get("lvd_value") + ":" + electronicLockMessage.getVolt() + currentMp.get("millivolt") + "/";

                        message += "-" + currentMp.get("lvd_value") + ":" + electronicLockMessage.getVolt() + currentMp.get("millivolt");
                    }

                    if (msg.length() > 2) {
                        if (!warnType.equals("0")) {
                            WarnInfo info = new WarnInfo();
                            if (dispatch != null) {
                                info.setDispatchId(dispatch.getId());
                            }
                            info.setLockCode(electronicLockMessage.getElNumber());
                            info.setWarnTime(electronicLockMessage.getTime());
                            ;
                            if (dispatch != null)
                                info.setTransportCode(dispatch.getPlatenumber());
                            info.setWarnpostion(electronicLockMessage.getLongitude() + "," + electronicLockMessage.getLatitude());
                            info.setPostionLat(electronicLockMessage.getLatitude() + "");
                            info.setPostionLng(electronicLockMessage.getLongitude() + "");
                            info.setWarnType(warnType);

                            info.setMsg(message);

                            warnInfoService.insertWarnInfoSample(info);

                            String msgResult = "";
                            if (currentMp != null) {
                                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                                msgResult = msg + currentMp.get("warn_date_time") + ":" + info.getCreationTime().format(formatter);
                            }
                            if (dispatch != null) {
                                String launchSiteId = dispatch.getLaunchsiteId();
                                String endSiteId = dispatch.getDestinationsiteId();
                                List<UserInfoDTO> launchList = userInfoService.findAllBySiteId(launchSiteId);
                                List<UserInfoDTO> endList = userInfoService.findAllBySiteId(endSiteId);
                                try {
                                    for (UserInfoDTO userInfoDTO : launchList) {
                                        websocketUDP.sendMessageTo(msgResult, userInfoDTO.getId());
                                    }
                                    for (UserInfoDTO userInfoDTO : endList) {
                                        websocketUDP.sendMessageTo(msgResult, userInfoDTO.getId());
                                    }

                                    List<UserInfoDTO> userList = userInfoService.findUserByRoleId();
                                    for (UserInfoDTO userInfoDTO : userList) {
                                        websocketUDP.sendMessageTo(msgResult, userInfoDTO.getId());
                                    }
                                } catch (IOException ex) {
                                }
                            }

                        }

                    }

                }
                elml.add(electronicLockMessage);
//                logger.info(electronicLockMessage.toString());

                count++;
            } catch (Exception e) {
                logger.error("Error in process message: ", e);
                continue;
            }
        }

        electronicLockMessageRepository.save(elml);

        logger.info("stop processing queque---------------------");
    }

}
